#!/usr/bin/env python

# Copyright (c) 2012, Michael Hermes
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer. Redistributions in binary
# form must reproduce the above copyright notice, this list of conditions and
# the following disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#--------------------
# Autopsy v0.05 04/24/12
# A Dungeon Crawl: Stone Soup character morgue analyzer
# Supports DC:SS v0.10
# Michael Hermes
# http://code.google.com/p/autopsy/
#
# Instructions:
# Run this file withing your morgue directory. A time-stamped log file
# containing your dead character's information will be created in your morgue
# directory.
#--------------------

from os import listdir
from sys import exit
from datetime import datetime
import re

from resources.lists import *


def populate_character_list(all_files):
    character_list = []
    for file_name in all_files:
        if file_name.startswith('morgue') and file_name.endswith('.txt'):
            character_list.append(file_name)
    return character_list


def find_line_number(string_to_find, file_to_search):
    line_counter = 0
    for line in file_to_search:
        if string_to_find in line:
            return line_counter
            break
        line_counter += 1


def header_info():
    header_text = ('---Autopsy v0.05 a Dungeon Crawl: Stone Soup Morgue ' \
    'Analyzer---\n\n')
    return header_text


def clean_date():
    date_string = str(datetime.now())
    date_string = re.sub("\D", "", date_string)
    return date_string


def character_count_text(number_of_characters):
    text = 'Your morgue contains ' + str(number_of_characters) + \
        ' dead adventurers.\n'
    return text


def get_gold_count(file_to_search):
    gold_line = find_line_number('Gold', file_to_search)
    gold_string = file_to_search[gold_line].rstrip()
    gold_string = gold_string[5:]
    gold_count = int(gold_string.split(' ')[0])
    return gold_count


def gold_summary(gold_total):
    summary = 'Total gold acquired: ' + str(sum(gold_total)) + '\n'
    return summary

#--------------------
# Game duration
#--------------------


def get_game_duration(file_to_search):
    duration_line = find_line_number('Time:', file_to_search)
    duration_string = file_to_search[duration_line].rstrip()
    game_duration = text_duration_to_seconds(duration_string[-8:])
    return game_duration


def text_duration_to_seconds(string_to_convert):
    hours = int(string_to_convert[0:2])
    minutes = int(string_to_convert[3:5])
    seconds = int(string_to_convert[6:8])
    seconds += hours * 3600
    seconds += minutes * 60
    return seconds


def seconds_to_text(total_seconds):
    hours = total_seconds / 3600
    minutes = (total_seconds % 3600) / 60
    seconds = total_seconds % 60
    text = str(hours) + ' hours, ' + str(minutes) + \
        ' minutes, ' + str(seconds) + ' seconds.'
    return text


def duration_summary(duration_in_seconds):
    total_seconds = sum(duration_in_seconds)
    average_game = seconds_to_text(sum(duration_in_seconds) /
        len(duration_in_seconds))
    shortest_game = seconds_to_text(min(duration_in_seconds))
    longest_game = seconds_to_text(max(duration_in_seconds))
    summary = 'Total game time:\t' + seconds_to_text(total_seconds) + \
        '\nAvg. game time:\t\t' + average_game + '\nShortest game:\t\t' + \
         shortest_game + '\nLongest game:\t\t' + longest_game + '\n\n'
    return summary


def get_total_turns(file_to_search):
    turns_line = find_line_number('Turns:', file_to_search)
    turns_string = file_to_search[turns_line].rstrip()
    turns_string = turns_string.split(': ')[1]
    total_turns = int(turns_string.split(', ')[0])
    return total_turns


def turns_summary(turn_count):
    summary = 'Total turns played: ' + str(sum(turn_count)) + '\n\n'
    return summary

#--------------------
# Race, Backgrounds, and Deities
#--------------------


def get_character_type(bkgnd):
    if (bkgnd == 'Fighter' or bkgnd == 'Gladiator' or bkgnd == 'Monk' or
            bkgnd == 'Hunter' or bkgnd == 'Assassin'):
        return 'Warrior'
    elif (bkgnd == 'Berserker' or bkgnd == 'Abyssal Knight' or
            bkgnd == 'Chaos Knight' or bkgnd == 'Death Knight' or
            bkgnd == 'Priest' or bkgnd == 'Healer'):
        return 'Zealot'
    elif (bkgnd == 'Skald' or bkgnd == 'Enchanter' or bkgnd == 'Transmuter' or
            bkgnd == 'Arcane Marskman' or bkgnd == 'Stalker' or
            bkgnd == 'Warper'):
        return 'Warrior-Mage'
    elif (bkgnd == 'Wizard' or bkgnd == 'Conjurer' or bkgnd == 'Summoner' or
            bkgnd == 'Necromancer' or bkgnd == 'Fire Elementalist' or
            bkgnd == 'Ice Elementalist' or bkgnd == 'Air Elementalist' or
            bkgnd == 'Earth Elementalist' or bkgnd == 'Venom Mage'):
        return 'Mage'
    elif (bkgnd == 'Artificer' or bkgnd == 'Wanderer'):
        return 'Adventurer'


def race_summary(race_count):
    summary = 'Races Played: \n-------------\n' + dict_column(race_count) + '\n'
    return summary


def background_summary(background_count):
    summary = ('Backgrounds Played: \n-------------\n' +
        dict_column(background_count) + '\n')
    return summary


def deities_summary(deity_count):
    summary = ('Deities worshiped: \n-------------\n' +
        dict_column(deity_count) + '\n')
    return summary

#--------------------
# Dictionary operations
#--------------------


def populate_dict(dict_to_search, player_file, line_to_search):
    for race in dict_to_search:
        if race in player_file[line_to_search]:
            dict_to_search[race] += 1
    return dict_to_search


def dict_column(dict_to_print):
    """Longest item is created to keep decent formatting and negate the need
    for futzing with tabs. Prints keys and values in a column."""
    column = ''
    longest_item = 0
    for item in dict_to_print:
        if len(item) > longest_item:
            longest_item = len(item)

    for item in dict_to_print:
        spaces = ' ' * (longest_item - len(item))
        column += str(item) + ': ' + spaces + str(dict_to_print[item]) + '\n'
    return column


def most_common(dict_to_search):
    return 0

#--------------------
# Main
#--------------------


def main():
    # Build a list of only character files in the directory
    all_files = listdir('.')
    character_list = populate_character_list(all_files)
    if len(character_list) == 0:
        print 'No character files found. Press enter to exit.'
        input('...')
        exit()

    # Local variables and empty containers
    deity_line = 4
    race_and_background_line = 3

    all_games_in_seconds = []
    gold_total = []
    turns_total = []

    # Loop through character list and fill containers
    for character in character_list:
        file_object = open(character, 'r').readlines()
        all_games_in_seconds.append(get_game_duration(file_object))
        gold_total.append(get_gold_count(file_object))
        turns_total.append(get_total_turns(file_object))
        race_count = populate_dict(race_count, file_object,
            race_and_background_line)
        backgrounds_count = populate_dict(backgrounds_count, file_object,
            race_and_background_line)
        deity_count = populate_dict(deity_count, file_object, deity_line)

    # Print containers into text file, write to disk
    log_file = open('Morgue Autopsy ' + clean_date() + '.txt', 'w')

    #---
    log_file.write(header_info())
    log_file.write(character_count_text(len(character_list)))
    log_file.write(gold_summary(gold_total))
    log_file.write(turns_summary(turns_total))
    log_file.write(duration_summary(all_games_in_seconds))
    log_file.write(race_summary(race_count))
    log_file.write(background_summary(backgrounds_count))
    log_file.write(deities_summary(deity_count))
    log_file.close()
    #---

    print 'Script completed successfully.'

main()
